// 切片 Slice 类型
// 另一个没有所有权的数据类型是 slice。slice 允许你引用集合中一段连续的元素序列，而不用引用整个集合。


// 编写一个函数，该函数接收一个字符串，并返回在该字符串中找到的第一个单词。如果函数在该字符串中并未找到空格，
// 则整个字符串就是一个单词，所以应该返回整个字符串
fn slice_1(s: &String) -> usize {
    // 将 String 转化为字节数组
    let bytes = s.as_bytes();

    // 而 enumerate 包装了 iter 的结果，将这些元素作为元组的一部分来返回。enumerate 返回的元组中，
    // 第一个元素是索引，第二个元素是集合中元素的引用
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}


fn slice_2() {
    let s = String::from("hello world");

    // 字符串切片，使用 &str 表示
    // 对于 Rust 的 .. range 语法，如果想要从索引 0 开始，可以不写两个点号之前的值
    let hello = &s[0..5];
    let hello = &s[..5];

    let world = &s[6..11];
    let world = &s[6..];
    let len = s.len();
    let world = &s[6..len];

    // 以下两种方式等价
    let slice = &s[0..len];
    let slice = &s[..];
}


// 重构上面的 slice_1 函数
fn second_word(s: &String) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[..i]
        }
    }
    &s[..]
}


// 其他类型的 slice 例如下面的数组切片
fn slice_3() {
    let a = [1, 2, 3, 4, 5];

    let slice = &a[1..3];
}